#include "header.h"
#include "SocketIO.hpp"
#include <errno.h>
namespace wd
{

int SocketIO::recvn(char * buff , int len)
{
   int left = len;
   char * pbuf = buff;

   while(left > 0)
   {
       int ret = recv(_fd , pbuf , left , 0);

       if(ret == -1 && errno == EINTR)
       {
           continue;
       }
       else if(ret == -1)
       {
           perror("recv");
           return ret;
       }
       else if(ret == 0)
       {
           return len - left;
       }
       // ret > 0 的情况
       else
       {
           left -= ret;
           pbuf += ret;
       }
   }

   return len;
}

int SocketIO::sendn(const char * buff , int len)
{
    int left = len;
    const char * pbuf = buff;

    while(left > 0)
    {
        int ret = send(_fd , pbuf , left , 0);

        if(ret < 0)
        {
            perror("send");
            return ret;
        }
        // ret > 0 的情况
        else
        {
            left -= ret;
            pbuf += ret;
        }
    }

    return len;
}

// maxlen : 表示一行的最大字节数
int SocketIO::readline(char * buff , int maxlen)
{
    // 获取的是一行数据，'\n'是作为消息边界出现的
    int left = maxlen - 1;
    char * pbuf = buff;
    // 表示读取的总得字节数
    int total = 0;

    while(left > 0)
    {
        int ret = recvPeek(pbuf , left);
        // 查找'\n'
        for(int i = 0 ; i < ret ; ++i)
        {
            // 找到了'\n'
            if(pbuf[i] == '\n')
            {
                // 表示包含 \n 的字节数
                int size = i + 1;
                ret = recvn(pbuf , size);
                total += ret;
                pbuf[i] = '\0';

                return total;
            }
        }
        // 这一次没有找到'\n' , 从内核接收缓冲区中移走
        ret = recvn(pbuf , ret);
        
        left  -= ret;
        pbuf  += ret;
        total += ret;
    }
    // 没有找到'\n'
    buff[maxlen - 1] = '\0';

    return maxlen -1;
}

int SocketIO::recvPeek(char * buff , int maxlen) const
{
    int ret = 0;

    do
    {
        ret = recv(_fd , buff , maxlen , MSG_PEEK);
    }
    while(ret == -1 && errno == EINTR);

    if(ret < 0)
    {
        perror("recv");
    }

    return ret;
}

} // end of namespace wd
